"""
ML_2i - машинное обучение собственной разработки 2-числовое.

Собственный основной компонент алгоритма.
"""
__logging__ = 1
def printt(txt):
	if __logging__ == 1:
		print(txt)

class new_Model():
	#input_count = 2
	#output_count = 2
	
	training_examples = []
	model = []
	
	def __init__(self):pass

	def start_training_v3(self, training_examples=[]):
		"""
		Каждому дню выдаётся свой список из сопоставлений [[[5,2], [2,6]]], [[2,4], [1,9]]]
		"""
		if training_examples != []:
			self.training_examples = training_examples
		
		#Problems checker LT
		chk_sts = 0
		if len(self.training_examples) > 0:
			chk_sts = 1
		if chk_sts == 0:
			printt("\n[ML_2i][new_Model][start_training_v3] ERROR: variable new_Model().training_examples empty or has other inputs and outputs.")
			exit(1)
		#---#
			
		#Preparation#
		printt("[ML_2i][new_Model][start_training_v3] INFO: preparation to training...")
		train_exs = self.training_examples
		data_lst = [[[100,100]]]
		# 1 - 100% (anyB - 200% or anyS - 0%)
		for i in range(len(train_exs[0][0])-1): # -1 так как первые 100% не учитываются
			data_lst.append([])
		#---#
			
		#Training
		printt("[ML_2i][new_Model][start_training_v3] INFO: training...")
		
		for train_ex in train_exs:
			perc_train_ex = train_ex # preobr_to_perc_v3(train_ex)
			perc_train_ex = [perc_train_ex[0][1:], perc_train_ex[1][1:]]
			
			for ids in range(len(perc_train_ex[0])):
				data_lst[ids+1].append([perc_train_ex[0][ids], perc_train_ex[1][ids]])
		printt("[ML_2i][new_Model][start_training_v3] INFO: training completed!")
		self.model = data_lst
				
	def new_prediction_v3(self, input_data):
		model = self.model
		if len(model) != len(input_data):
			printt("[ML_2i][new_Model][new_prediction_v3] ERROR: length input_data not equal training input_data.")
			exit(1)
		
		printt("[ML_2i][new_Model][new_prediction_v3] INFO: starting prediction...")
		
		#Prepairing
		input_data_perc= preobr_to_perc_v3([input_data, input_data])[0]
		outpt_lst = []
		p100 = input_data[0]
		for idnn, inpts in enumerate(input_data_perc):
			
			to_sovpd = []
			nto_sovpd = []
			for idn, mdl in enumerate(model[idnn]):
				if len(to_sovpd) == 0 or to_sovpd[0] > abs(mdl[0] - inpts):
					to_sovpd = [abs(mdl[0] - inpts), mdl[1], idn]
					
			# Удалить при возврате
			#printt(p100, to_sovpd)
			outpt_lst.append(p100/100*to_sovpd[1]) # в теории должно быть правильным (так и есть)
			#outpt_lst.append((100/to_sovpd[1]*p100)) #последнее лучшее
			#outpt_lst.append((to_sovpd[1]/100*p100)) # плохо работает
		printt("[ML_2i][new_Model][new_prediction_v3] INFO: prediction completed!")
		return input_data, outpt_lst
		
	def start_training_v4(self, training_examples=[]):
		"""
		Каждое сопоставление используется для разных дней
		"""
		if training_examples != []:
			self.training_examples = training_examples
		
		#Problems checker LT
		chk_sts = 0
		if len(self.training_examples) > 0:
			chk_sts = 1
		if chk_sts == 0:
			printt("\n[ML_2i][new_Model][start_training_v4] ERROR: variable new_Model().training_examples empty or has other inputs and outputs.")
			exit(1)
		#---#
			
		#Preparation#
		printt("[ML_2i][new_Model][start_training_v4] INFO: preparation to training...")
		train_exs = self.training_examples #[1]
		#p100 = self.training_examples[0]
		data_lst = []
		
		#Training
		printt("[ML_2i][new_Model][start_training_v4] INFO: training...")
		
		for train_ex in train_exs:
			perc_train_ex = train_ex #preobr_to_perc_v4(train_ex, train_ex[0][0])
			#perc_train_ex = [perc_train_ex[0][1:], perc_train_ex[1][1:]]
			
			
			for ids in range(len(perc_train_ex[0])):
				data_lst.append([perc_train_ex[0][ids], perc_train_ex[1][ids]])
				data_lst.append([perc_train_ex[1][ids], perc_train_ex[0][ids]])
		printt("[ML_2i][new_Model][start_training_v4] INFO: training completed!")
		self.model = data_lst#[p100, data_lst]
	
	def new_prediction_v4(self, input_data):
		model = self.model#[1]
		p100 = medium_arifmetical(input_data)#p100 = self.model[0]
		#if len(model) != len(input_data):
			#printt("[ML_2i][new_Model][new_prediction_v4] ERROR: length input_data not equal training input_data.")
			#exit(1)
		
		printt("[ML_2i][new_Model][new_prediction_v4] INFO: starting prediction...")
		
		#Prepairing
		input_data_perc= preobr_to_perc_v4([input_data, []], p100)[0] # p100 X[1:]
		
		outpt_lst = []
		for inpts in input_data_perc:
			
			to_sovpd = []
			nto_sovpd = []
			for idn, mdl in enumerate(model):
				if len(to_sovpd) == 0 or to_sovpd[0] > abs(mdl[0] - inpts):
					nto_sovpd = to_sovpd
					to_sovpd = [abs(mdl[0] - inpts), mdl[1], idn]
					
			# Удалить при возврате
			outpt_lst.append(p100/100*to_sovpd[1]) # в теории должно быть правильным (так и есть)
			#outpt_lst.append((100/to_sovpd[1]*p100)) #последнее лучшее
				
				#---///---#
				
				#printt()
			
		printt("[ML_2i][new_Model][new_prediction_v4] INFO: prediction completed!")
		#outpt_lst.reverse()
		return input_data, outpt_lst
		
		

def show_graph(plot1, plot2=[], plot3=[], plot4=[]):
	import matplotlib.pyplot as plt
	
	fig, ax = plt.subplots()
	ax.plot(plot1[0], plot1[1], label=plot1[2])
	if plot2 != []:
		ax.plot(plot2[0], plot2[1], label=plot2[2])
	if plot3 != []:
		ax.plot(plot3[0], plot3[1], label=plot3[2])
	if plot4 != []:
		ax.plot(plot4[0], plot4[1], label=plot4[2])
		
	ax.legend()
	plt.show()
	
	#plt.savefig('plot.png', dpi=300, bbox_inches='tight')
	printt("[ML_2i][show_graph] INFO: image saved.")


def save_graph(plot1, plot2=[], plot3=[], plot4=[]):
	import matplotlib.pyplot as plt

	fig, ax = plt.subplots()
	ax.plot(plot1[0], plot1[1], label=plot1[2])
	if plot2 != []:
		ax.plot(plot2[0], plot2[1], label=plot2[2])
	if plot3 != []:
		ax.plot(plot3[0], plot3[1], label=plot3[2])
	if plot4 != []:
		ax.plot(plot4[0], plot4[1], label=plot4[2])

	ax.legend()

	plt.savefig('plot.png', dpi=300, bbox_inches='tight')
	printt("[ML_2i][save_graph] INFO: image saved.")
	
def show_graph_iow(inpt, out, wllb, outname="Out"):
	#wllb
	if len(wllb) > 1:
		show_graph([range(len(inpt)), inpt, "Input"],
		[range(len(inpt)-1,len(inpt)+len(out)-1), out, outname],
		[range(len(inpt)-1,len(inpt)+len(wllb)-1), wllb, "Will be"])
	else:
		show_graph([range(len(inpt)), inpt, "Input"],
		[range(len(inpt)-1,len(inpt)+len(out)-1), out, outname])
	
def show_graph_inout(inpt, outpt):
	import matplotlib.pyplot as plt
	outpt.reverse()
	outpt.append(inpt[len(inpt)-1])
	outpt.reverse()
	show_graph([range(len(inpt)), inpt, "Input"], [range(len(inpt)-1,len(inpt)+len(outpt)-1), outpt, "Out"])


def convert_to_trx_v3(data, delit):
	tr_ex = []
	for ex in range(len(data)-1-delit*2):
	   try:tr_ex.append([data[ex:ex+delit], data[ex+delit:ex+delit*2]])
	   except Exception as e:printt(e)
	return tr_ex


def convert_to_trx_v4(data, delit):
	#tr_ex = [data[0], []]
	tr_ex = []
	for ex in range(len(data)-delit*2+1):

	   adlst = [data[ex:ex+delit], data[ex+delit:ex+delit*2]]
	   p100 = medium_arifmetical(adlst[0]+adlst[1])
	   
	   #printt(adlst, p100)
	   preobred = preobr_to_perc_v4(adlst, p100)
	   try:tr_ex.append(preobred) #[1]
	   except Exception as e:printt(e)
	return tr_ex

	
def medium_smooth_graph(inpt, outpt, srpo=4):
	#=ЕСЛИ(СТРОКА()<12;НД();СРЗНАЧ(СМЕЩ(C2;-9;0;10;1))
	
	fulunt =  inpt+outpt
	
	# Среднее по прошлым srpoм — следующее #
	srpo = srpo
	foutpt = []
	for i in range(len(outpt)):
		i += 1
		lst = fulunt[len(inpt)-srpo+i: len(inpt)+i]
		srd = 0
		for i in lst:
			srd += i
		srd = srd/srpo
		foutpt.append(srd)
	#---///---#
	return foutpt
	
def preobr_to_perc_v3(trx):
		train_ex = trx
		if 1:
			#Преобразование чисел в %
			perc_train_ex = [[], []]
			
			zadaval = 0
			in_first = train_ex[0][0]
			out_first = train_ex[1][0]
			
			for i in train_ex[0]:
				#i += 1
				perc_train_ex[0].append(100/in_first*i)#in_mnzx*i+(100-train_ex[0][0]*in_mnzx))
			for i in train_ex[1]:
				#i += 1
				perc_train_ex[1].append(100/out_first*i)#out_mnzx*i+(100-train_ex[1][0]*out_mnzx))
		return perc_train_ex
	

def preobr_to_perc_v4(trx, fst):
		train_ex = trx
		if 1:
			#Преобразование чисел в %
			perc_train_ex = [[], []]			
			#printt(len(train_ex[0]))
			for i in train_ex[0]:
				#i += 1
				#printt(100/fst*i)
				perc_train_ex[0].append(100/fst*i)
			for i in train_ex[1]:
				#i += 1
				perc_train_ex[1].append(100/fst*i)#out_mnzx*i+(100-train_ex[1][0]*out_mnzx))
		return perc_train_ex
		
def medium_arifmetical(lst):
	p100 = 0
	for el in lst:
	   	p100 += el
	return p100/len(lst)
